package engine.video.blit;

import common.Coordinate;
import common.Rectangle;

/**
 * Blitter
 **/

public class Blitter {
	public Blitter(PixelBuffer_I targetBuffer) {
		TargetBuffer = targetBuffer;
		_Clipper = new ClipInfo();
		_DestRect = new Rectangle(0,0, targetBuffer.getWidth(), targetBuffer.getHeight());
	}

	public final PixelBuffer_I TargetBuffer;
	private ClipInfo _Clipper;
	private Rectangle _DestRect;

	public void blit(SpriteInfo sprite, int ofsX, int ofsY) {
		if(sprite == null || !sprite.isValid()){
			return;
		}
		_DestRect.Width = TargetBuffer.getWidth();
		_DestRect.Height = TargetBuffer.getHeight();
		_DestRect.X = ofsX;
		_DestRect.Y = ofsY;
		
		if(!_Clipper.calculate(sprite.Image, sprite.ClipRect, TargetBuffer, _DestRect)) {
			return;
		}
		if(sprite.Mask == null) {
			blit(sprite.Image, TargetBuffer, _Clipper, BlitMode_E.COPY);
		} else {
			blit(sprite.Mask, TargetBuffer, _Clipper, BlitMode_E.AND);
			blit(sprite.Image, TargetBuffer, _Clipper, BlitMode_E.OR);
		}
	}

	public void blit(PixelBuffer_I source, PixelBuffer_I dest, ClipInfo clip,
			BlitMode_E mode) {
		byte[] srcData = source.getScan0();
		int sOfs = clip.SrcOffset;
		int sStride = clip.SrcStride;

		byte[] dstData = dest.getScan0();
		int dOfs = clip.DstOffset;
		int dStride = clip.DstStride;

		int rows = clip.Rows;
		int cols = clip.Cols;
		switch (mode) {
			case COPY:
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] = srcData[sOfs++];
					}
					sOfs += sStride;
					dOfs += dStride;
				}
				break;
			case AND:
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] &= srcData[sOfs++];
					}
					sOfs += sStride;
					dOfs += dStride;
				}
				break;
			case OR:
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] |= srcData[sOfs++];
					}
					sOfs += sStride;
					dOfs += dStride;
				}
				break;
			case XOR:
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] ^= srcData[sOfs++];
					}
					sOfs += sStride;
					dOfs += dStride;
				}
				break;
			default :
				// Unknown mode.
				break;
		}
	}
	
	public void blitRectangle(byte color, Rectangle source, PixelBuffer_I dest, BlitMode_E mode) {
		_Clipper.calculate(dest, source);
		if(!_Clipper.Valid) {
			return;
		}
		byte[] dstData = dest.getScan0();
		int dOfs = _Clipper.DstOffset;
		int dStride = _Clipper.DstStride;

		int rows = _Clipper.Rows;
		int cols = _Clipper.Cols;
		switch (mode) {
			case COPY:
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] = color;
					}
					dOfs += dStride;
				}
				break;
			case AND:
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] &= color;
					}
					dOfs += dStride;
				}
				break;
			case OR:
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] |= color;
					}
					dOfs += dStride;
				}
				break;
			case XOR:
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] ^= color;
					}
					dOfs += dStride;
				}
				break;
			default :
				for (int y = 0; y < rows; y++) {
					for (int x = 0; x < cols; x++) {
						dstData[dOfs++] = color;
					}
					dOfs += dStride;
				}
				break;
		}
	}
}